package com.example.handdet;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.Intent;
import android.graphics.RectF;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.TextureView;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.view.View;


import android.util.Log;

import android.graphics.Matrix;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Color;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.handdet.databinding.ActivityMainBinding;
import com.example.handdet.guesture.Bbox;
import com.example.handdet.guesture.NanoDet;

import androidx.camera.core.CameraX;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageAnalysisConfig;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.PreviewConfig;
import androidx.camera.core.UseCase;
import androidx.core.app.ActivityCompat;

import android.content.pm.PackageManager;
import android.widget.Toast;


import java.io.File;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    private final static String TAG = "MainActivity";

    // camera select
    public static CameraX.LensFacing CAMERA_ID = CameraX.LensFacing.BACK;

    //detect result msg
    private static final int DETECT_RESULT_HAND = 55;
    //detect result msg
    private static final int DETECT_RESULT_FACE= 66;
    // quest source
    private static final int REQUEST_CAMERA = 1;
    private static final int REQUEST_PICK_IMAGE = 2;

    private String baseTag ="";
    protected ExecutorService mExcutor= Executors.newCachedThreadPool();

    // permission request
    private static String[] PERMISSIONS_CAMERA = {
            Manifest.permission.CAMERA,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE
    };

    // flags
    private AtomicBoolean detecting = new AtomicBoolean(false);
    private AtomicBoolean detectPhoto = new AtomicBoolean(false);
    private AtomicBoolean face_detecting = new AtomicBoolean(false);

    // view
    private ImageView resultImageView;
    private SeekBar nmsSeekBar;
    private SeekBar labelSeekBar;
    private TextView thresholdTextview;
    private TextView tvInfo;
    private double threshold = 0.5, nms_threshold=0.5;
    private TextureView viewFinder;
    private ImageView voice_hi;
    protected Bitmap mutable_bitmap;
    public Switch faceSwitch,handSwitch;
    private boolean facedetect = false,handdetect = true;


    // view format
    final String format = "Threshold: %.2f, NMS: %.2f";

    // exec
    ExecutorService detectService = Executors.newSingleThreadExecutor();
    Bitmap bitmap;

    // 设置是否存图
    private AtomicBoolean saveImageFlag = new AtomicBoolean(false);
    private MediaPlayer mediaPlayer = new MediaPlayer();//实例化对象

    // fps
    double total_fps = 0;
    int fps_count = 0;
private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == DETECT_RESULT_HAND) {// wardrobe count
                if(msg.obj.equals("five")){
                    voice_hi.setVisibility(View.VISIBLE);
                    if(!mediaPlayer.isPlaying()) {
                        mediaPlayer.start();
                    }
                }else if(msg.obj.equals("ten")){
                }else if(msg.obj.equals("ok")){

                }
            }else if(msg.what == DETECT_RESULT_FACE){

            }
            }
        };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        int info = cameraCheck();
        if(info!=0){
            return;
        }

        // init model
        NanoDet.init(getAssets(), false);

        // display region
        resultImageView = findViewById(R.id.imageView);
        thresholdTextview = findViewById(R.id.valTxtView);
        tvInfo = findViewById(R.id.tv_info);
        nmsSeekBar = findViewById(R.id.nms_seek);
        labelSeekBar = findViewById(R.id.threshold_seek);
        voice_hi = findViewById(R.id.voice_hi);

        // init
        threshold = 0.4f;
        nms_threshold = 0.5f;


        nmsSeekBar.setProgress((int)(nms_threshold*100));
        labelSeekBar.setProgress((int)(threshold*100));
        thresholdTextview.setText(String.format(Locale.ENGLISH, format, threshold, nms_threshold));

        setSeekBarListener();

        Button inference = findViewById(R.id.button);
        inference.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType("image/*");
                startActivityForResult(intent, REQUEST_PICK_IMAGE); // replace
            }
      });

        resultImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                detectPhoto.set(false);
            }
        });

        // 存图
        Button saveImages = findViewById(R.id.save_image_btn);

        saveImages.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!saveImageFlag.get()){
                    saveImages.setText("取消保存");
                    saveImageFlag.set(true);
                    Log.i(TAG, "Set save images");
                }else{
                    saveImages.setText("保存图片");
                    saveImageFlag.set(false);
                    Log.i(TAG, "Cancel save images");
                }
            }
        });

        viewFinder = findViewById(R.id.view_finder);
        viewFinder.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
                updateTransform();
            }
        });

        viewFinder.post(new Runnable() {
            @Override
            public void run() {
                startCamera();
            }
        });
        faceSwitch =findViewById(R.id.switch_face);
        handSwitch =findViewById(R.id.switch_hand);
        faceSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked){
                    facedetect = true;
                    handdetect = false;
                }else {
                    //未选中状态 可以做一些操作
                    facedetect = false;
                }
            }
        });
        handSwitch.setChecked(true);
        handSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked){
                    handdetect = true;
                    facedetect = false;
                }else {
                    //未选中状态 可以做一些操作
                    handdetect = false;
                }
            }
        });
        initMediaPlayer();
    }
    private void initMediaPlayer(){
        /*
        try{
            File file = new File("mnt/sdcard/voice_origin/","id3.wav");
            if(file !=null)//想要添加判断 是否找到music.map3
                Toast.makeText(MainActivity.this,"the sd have not music.mp3",Toast.LENGTH_SHORT).show();

            mediaPlayer.setDataSource(file.getPath());//指定音频路径
            mediaPlayer.prepare();
        }catch (Exception e){
            e.printStackTrace();
        }

         */
        mediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.id3);
    }
    private void updateTransform() {
        Matrix matrix = new Matrix();
        // Compute the center of the view finder
        float centerX = viewFinder.getWidth() / 2f;
        float centerY = viewFinder.getHeight() / 2f;

        float[] rotations = {0, 90, 180, 270};
        // Correct preview output to account for display rotation
        // float rotationDegrees = rotations[viewFinder.getDisplay().getRotation()];
        // 修改预览窗口的旋转角度
        float rotationDegrees = rotations[2];

        matrix.postRotate(-rotationDegrees, centerX, centerY);

        // Finally, apply transformations to our TextureView
        viewFinder.setTransform(matrix);
    }

    private int cameraCheck()    {
        // permission check then prompt
        int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    this,
                    PERMISSIONS_CAMERA,
                    REQUEST_CAMERA
            );
            // finish();
        }

        // check camera
        PackageManager pm = getPackageManager();
        if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            CAMERA_ID = CameraX.LensFacing.BACK;
            return 0;
        }

        if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)){
            CAMERA_ID = CameraX.LensFacing.FRONT;
            return 0;
        }

        return -1;
    }

    private void setSeekBarListener(){
        nmsSeekBar.setOnSeekBarChangeListener(
                new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                        nms_threshold = i / 100.f;
                        thresholdTextview.setText(String.format(Locale.ENGLISH, format, threshold, nms_threshold));
                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                }
        );

        labelSeekBar.setOnSeekBarChangeListener(
                new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                        threshold = i / 100.f;
                        thresholdTextview.setText(String.format(Locale.ENGLISH, format, threshold, nms_threshold));
                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                }
        );
    }
    /**
     * 人脸识别
     * */
    private void face_detect() throws Exception {
        Log.d(TAG, "face_detect ...in ...");
        if(face_detecting.get()){
           return;
        }
            face_detecting.set(true);

        if(mExcutor == null){
            face_detecting.set(false);
            return;
        }
        mExcutor.submit(new Runnable() {
            @Override
            public void run() {
                UserResponse faceResponse= null;
                try {
                    faceResponse = FaceDetectUtil.getInstance().face_detect();
                    face_detecting.set(false);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if(faceResponse.statusCode==200){
                    Log.d(TAG, "face_detect ...response ok  ...");
                    String retCode=faceResponse.body.getString("retCode");
                    if(retCode!="00000"){
                        Log.d(TAG, "face_detect ...failed ...");
                    }

                    JSONObject data=faceResponse.body.getJSONObject("data");
                    JSONArray attributs=data.getJSONArray("faceAttrs");
                    JSONObject attributeObject=attributs.getJSONObject(0);
                    String gender= attributeObject.getString("gender");
                    Log.d(TAG,"face_detect gender is  $gender");
                    if(gender.equals("female")){
                        Log.d(TAG,"parse gender ....$gender");
                        baseTag="女";
                    }else if(gender.equals("male")){
                        Log.d(TAG,"parse gender ....$gender");
                        baseTag="男";
                    }
                    detecting.set(false);
                    Log.d(TAG, "face_detect ...SUCCESS ..."+baseTag);
                }else{
                    Log.d(TAG, "face_detect ...failed ...");
                }
                Log.d(TAG, "face_detect ...out ...");
            }

        });


    }

    private void startCamera(){
        // camera bind
         CameraX.unbindAll();

        // preview
        PreviewConfig previewConfig = new PreviewConfig.Builder()
                .setLensFacing(CAMERA_ID)
//                .setTargetResolution(new Size(1440, 1080))
                // .setTargetRotation(Surface.ROTATION_180)          // rotation angle
                .build();

        Preview preview = new Preview(previewConfig);

        preview.setOnPreviewOutputUpdateListener(
                new Preview.OnPreviewOutputUpdateListener() {
                    @Override
                    public void onUpdated(Preview.PreviewOutput output) {
                        ViewGroup parent = (ViewGroup) viewFinder.getParent();
                        parent.removeView(viewFinder);
                        parent.addView(viewFinder, 0);
                        viewFinder.setSurfaceTexture(output.getSurfaceTexture());

                        updateTransform();
                    }
                }
        );

        // detect analyzer
        DetectAnalyzer detectAnalyzer = new DetectAnalyzer();
        CameraX.bindToLifecycle(this, preview, gainAnalyzer(detectAnalyzer));

    }

    private class DetectAnalyzer implements ImageAnalysis.Analyzer {
        @Override
        public void analyze(ImageProxy image, final int rotationDegrees) {
            if(handdetect) {
                detect(image, rotationDegrees);
            }else if(facedetect){
                try {
                    face_detect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private UseCase gainAnalyzer(DetectAnalyzer detectAnalyzer) {
        ImageAnalysisConfig.Builder analysisConfigBuilder = new ImageAnalysisConfig.Builder();
        analysisConfigBuilder.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE);
        // analysisConfigBuilder.setTargetRotation(Surface.ROTATION_180); // 旋转180度
        // analsisConfigBuilder.setTargetResolution(DEFAULT_TARGET_RESOLUTION);  // 输出预览图像尺寸
        // analysisConfigBuilder.setTargetResolution(new Size(1440, 1080));
        ImageAnalysisConfig config = analysisConfigBuilder.build();
        ImageAnalysis analysis = new ImageAnalysis(config);
        analysis.setAnalyzer(detectAnalyzer);
        return analysis;
    }

    private void detect(ImageProxy image, int rotation_angle){
        // if detect, return
        if(detecting.get() || detectPhoto.get()){
            return;
        }
        detecting.set(true);

        // timer

        // type convert
        bitmap = ImageConvert.imageToBitmap(image);
        if(detectService == null){
            detecting.set(false);
            return;
        }

        detectService.execute(new DetectRunable());

    }

    private class DetectRunable implements Runnable
    {
        @Override
        public void run() {
            long start_time = System.currentTimeMillis();

            Matrix matrix = new Matrix();
            matrix.postRotate(90);

            int width = bitmap.getWidth();
            int height = bitmap.getHeight();

            Bitmap bitmap_rotate = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);

            Bbox[] result = NanoDet.detect(bitmap_rotate, threshold, nms_threshold);

            if (result == null){
                detecting.set(false);
                return;
            }

            // save detect image
            if(saveImageFlag.get()){
                Log.i(TAG, "Saving Images to SDCard...");
                if(result.length > 0){
                    Utils.saveBitmapToSDCard(bitmap, "nanodet_" + result[0].getLabel());
                    // Utils.saveBitmapToSDCard(bitmapsrc, result[0].getLabel());
                }else {
                    Utils.saveBitmapToSDCard(bitmap, "nanodet_" + "background");
                    // Utils.saveBitmapToSDCard(bitmapsrc, "background");
                }
            }

            mutable_bitmap = bitmap_rotate.copy(Bitmap.Config.ARGB_8888, true);

            mutable_bitmap = drawBboxRects(mutable_bitmap, result);
            //多个手势不唤醒

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    detecting.set(false);
                    if(detectPhoto.get()){
                        return;
                    }
                    if(result.length>1){
                        Toast.makeText(getBaseContext(),"检测到多个手势！",Toast.LENGTH_LONG);
                    }else if(result.length==1){
                        if(result[0].getLabel().equals("five")){
                            voice_hi.setVisibility(View.VISIBLE);
                            if(!mediaPlayer.isPlaying()) {
                                mediaPlayer.start();
                            }
                        }else if(result[0].getLabel().equals("ok")){
                            voice_hi.setVisibility(View.INVISIBLE);
                        }else if(result[0].getLabel().equals("ten")){
                            voice_hi.setVisibility(View.INVISIBLE);
                        }
                    }
                    resultImageView.setImageBitmap(mutable_bitmap);

                    long end_time = System.currentTimeMillis();
                    long dur = end_time - start_time;
                    float fps = (float)(1000. / dur);

                    total_fps = (total_fps == 0) ? fps : (total_fps + fps);
                    fps_count++;

//                    tvInfo.setText(String.format(Locale.CHINESE,
//                            "%s\nSize: %dx%d\nTime: %.3f s\nFPS: %.3f\nAVG_FPS: %.3f",
//                            "Nanodet", height, width, dur / 1000.0, fps, (float) total_fps / fps_count));
                    tvInfo.setText(String.format(Locale.CHINESE,
                            "%s\nSize: %dx%d\nFPS: %.3f\nAVG_FPS: %.3f",
                            "Nanodet", height, width, fps, (float) total_fps / fps_count));

                }
            });

        }

        protected Bitmap drawBboxRects(Bitmap mutableBitmap, Bbox[] results) {
            if (results == null || results.length <= 0) {
                return mutableBitmap;
            }
            Canvas canvas = new Canvas(mutableBitmap);
            final Paint boxPaint = new Paint();
            boxPaint.setAlpha(200);
            boxPaint.setStyle(Paint.Style.STROKE);
            boxPaint.setStrokeWidth(4 * mutableBitmap.getWidth() / 800.0f);
            boxPaint.setTextSize(40 * mutableBitmap.getWidth() / 800.0f);
            for (Bbox box : results) {
                boxPaint.setColor(getColor(box.label));
                boxPaint.setStyle(Paint.Style.FILL);
                canvas.drawText(box.getLabel() + String.format(Locale.CHINESE, " %.3f", box.getScore()), box.x0 + 3, box.y0 + 40 * mutableBitmap.getWidth() / 1000.0f, boxPaint);
                        boxPaint.setStyle(Paint.Style.STROKE);
                RectF rect = new RectF(box.x0, box.y0, box.x1, box.y1);
                canvas.drawRect(rect, boxPaint);
            }
            return mutableBitmap;
        }

        private int getColor(int label){
            Random random = new Random(label);
            return Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256));
        }
    }

}